/*
 * Copyright (C) 2011, EADS France
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 */
package xowl.gmi.view.diagram;

import java.util.List;

/**
 *
 * @author Laurent WOUTERS
 */
public class RepetitionWidget extends Widget {
    private static final Couple minSize = new Couple(25, 25);
    private static final double padding = 10;
    
    public static interface Actions {
        boolean acceptFlavor(java.awt.datatransfer.DataFlavor flavor);
        boolean acceptData(java.awt.datatransfer.DataFlavor flavor, Object data);
        boolean drop(java.awt.datatransfer.DataFlavor flavor, Object data, int index);
    }
    
    private Actions actions;
    private Container inner;
    private xowl.gmi.view.DropHandler dropHandler;
    private boolean isOrdered;
    private Couple hovering;
    private boolean accepting;
    
    public xowl.gmi.view.DropHandler onMouseDrop() { return dropHandler; }
    
    public RepetitionWidget(Actions actions, GMIAlignment alignment, boolean isPacked, boolean isOrdered) {
        this.actions = actions;
        this.inner = new Container(alignment, isPacked);
        this.isOrdered = isOrdered;
        this.dropHandler = new xowl.gmi.view.DropHandler() {
            @Override public int getSupportedActions() { return javax.swing.TransferHandler.COPY_OR_MOVE; }
            @Override public boolean acceptFlavor(java.awt.datatransfer.DataFlavor flavor) { return RepetitionWidget.this.actions.acceptFlavor(flavor); }
            @Override public boolean acceptData(java.awt.datatransfer.DataFlavor flavor, Object data) {
                accepting  = RepetitionWidget.this.actions.acceptData(flavor, data);
                return accepting;
            }
            @Override public boolean drop(java.awt.datatransfer.DataFlavor flavor, Object data, java.awt.Point location) {
                return RepetitionWidget.this.actions.drop(flavor, data, inner.getInsertionIndex(new Couple(hovering.x - padding, hovering.y - padding)));
            }
        };
    }
    
    public void addChild(Widget child) { inner.addChild(child); }
    public void addChild(Widget child, int index) { inner.addChild(child, index); }
    public void removeChild(Widget child) { inner.removeChild(child); }
    
    @Override protected void buildStackChildren(List<Widget> stack, Couple input) {
        inner.buildStackAt(stack, input);
    }
    
    @Override public Couple getMinSize() {
        if (inner.children.isEmpty())
            return minSize;
        return inner.getMinSize().plus(padding * 2);
    }
    @Override public Couple getMaxSize() {
        if (inner.children.isEmpty())
            return MAXSIZE;
        Couple dim = inner.getMaxSize();
        if (dim == MAXSIZE)
            return dim;
        return dim.plus(padding * 2);
    }
    @Override public Couple layout() {
        if (inner.children.isEmpty()) {
            dimension = minSize;
        } else {
            dimension = inner.layout().plus(padding * 2);
            inner.setPosition(new Couple(padding, padding));
        }
        return dimension;
    }
    @Override public Couple layout(Couple bounds) {
        if (inner.children.isEmpty()) {
            dimension = bounds;
        } else {
            Couple innerBounds = bounds.minus(padding * 2);
            innerBounds = new Couple(Math.max(0, innerBounds.x), Math.max(0, innerBounds.y));
            dimension = inner.layout(innerBounds).plus(padding * 2);
            inner.setPosition(new Couple(padding, padding));
        }
        return dimension;
    }
    
    @Override public void paint(java.awt.Graphics2D g2d, float alpha, DiagramStyle style, Couple offset) {
        if (hovering != null && accepting)
            paintBackground(g2d, style, offset);
        inner.paint(g2d, alpha, style, position.plus(offset));
        if (hovering != null && accepting && isOrdered)
            paintSeparator(g2d, style, offset);
    }
    @Override protected void exportSVG(org.w3c.dom.Document doc, org.w3c.dom.Element parent, float alpha, DiagramStyle style, Couple offset) {
        inner.exportSVG(doc, parent, alpha * transparency, style, position.plus(offset));
    }
    
    @Override public boolean onMouseEnter(UserState state, Couple local) {
        if (state != UserState.Dragging) return false;
        hovering = local;
        accepting = false;
        return true;
    }
    @Override public boolean onMouseLeave() {
        if (hovering == null) return false; 
        hovering = null;
        accepting = false;
        return true;
    }
    
    private void paintBackground(java.awt.Graphics2D g2d, DiagramStyle style, Couple poff) {
        g2d.setPaint(new java.awt.Color(style.dropColor.getRed(), style.dropColor.getGreen(), style.dropColor.getBlue(), 30));
        g2d.setStroke(new java.awt.BasicStroke(1));
        double bound = dimension.x + dimension.y;
        for (double i=10; i<bound; i+=10) {
            double sx = poff.x + position.x + i;
            double sy = poff.y + position.y;
            double ex = poff.x + position.x;
            double ey = poff.y + position.y + i;
            if (sx > (poff.x + position.x + dimension.x)) {
                double offset = i - dimension.x;
                sx -= offset;
                sy += offset;
            }
            if (ey > (poff.y + position.y + dimension.y)) {
                double offset = i - dimension.y;
                ey -= offset;
                ex += offset;
            }
            g2d.drawLine((int)sx, (int)sy, (int)ex, (int)ey);
        }
    }
    private void paintSeparator(java.awt.Graphics2D g2d, DiagramStyle style, Couple poff) {
        double offset = inner.getInsertionOffset(hovering.minus(padding)) + padding;
        g2d.setColor(style.inserterColor);
        g2d.setStroke(new java.awt.BasicStroke(style.inserterThickness));
        if (inner.isAlignmentHorizontal()) {
            offset += poff.x + position.x;
            int s = (int)(poff.y + position.y);
            int e = (int)(poff.y + position.y + dimension.y);
            g2d.drawLine((int)offset, s + 5, (int)offset, e - 5);
            g2d.drawLine((int)offset - 5, s, (int)offset, s + 5);
            g2d.drawLine((int)offset + 5, s, (int)offset, s + 5);
            g2d.drawLine((int)offset - 5, e, (int)offset, e - 5);
            g2d.drawLine((int)offset + 5, e, (int)offset, e - 5);
        } else if (inner.isAlignmentVertical()) {
            offset += poff.y + position.y;
            int s = (int)(poff.x + position.x);
            int e = (int)(poff.x + position.x + dimension.x);
            g2d.drawLine(s + 5, (int)offset, e - 5, (int)offset);
            g2d.drawLine(s, (int)offset - 5, s + 5, (int)offset);
            g2d.drawLine(s, (int)offset + 5, s + 5, (int)offset);
            g2d.drawLine(e, (int)offset - 5, e - 5, (int)offset);
            g2d.drawLine(e, (int)offset + 5, e - 5, (int)offset);
        }
    }
}
